﻿namespace Morus.Infrastructure
{
    using System;
    using System.Linq.Expressions;

    public abstract class Specification<T> : ISpecification<T>
         where T : class
    {
        public ISpecification<T> And(ISpecification<T> other)
        {
            Check.Argument.IsNotNull(other, "other");

            return new AndSpecification<T>(this, other);
        }

        public ISpecification<T> Or(ISpecification<T> other)
        {
            Check.Argument.IsNotNull(other, "other");

            return new OrSpecification<T>(this, other);
        }

        public ISpecification<T> Not()
        {
            return new NotSpecification<T>(this);
        }

        public ISpecification<T> AndNot(ISpecification<T> other)
        {
            Check.Argument.IsNotNull(other, "other");

            return new AndNotSpecification<T>(this, other);
        }

        public virtual bool IsStatisfiedBy(T target)
        {
            return this.Expression.Compile()(target);
        }

        public static ISpecification<T> Eval(Expression<Func<T, bool>> expression)
        {
            return new DirectSpecification<T>(expression);
        }

        public static ISpecification<T> Any()
        {
            return new AnySpecification<T>();
        }

        public abstract Expression<Func<T, bool>> Expression { get; }
    }

    public abstract class Spec<T> : Specification<T>
        where T : class
    {
    }
}
